package lin

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"embed"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"io/fs"
	"os"
	"path/filepath"
	"strings"
	"time"
)

func any_到文本(任意数据 any) (返回值 string) {
	if 任意数据 == nil {
		return
	}
	switch 当前值 := 任意数据.(type) {
	case string:
		返回值 = 当前值
		return
	case time.Time:
		返回值 = 当前值.Format("2006-01-02 15:04:05")
		return
	case []any, []map[string]any:
		JSON, err := json.Marshal(当前值)
		if err != nil {
			返回值 = "[]"
			return
		}
		返回值 = string(JSON)
	case map[string]any:
		JSON, err := json.Marshal(当前值)
		if err != nil {
			返回值 = "{}"
			return
		}
		返回值 = string(JSON)
	case []byte:
		返回值 = string(当前值)
		return
	case float64:
		if float64(int(当前值)) == 当前值 {
			返回值 = fmt.Sprintf("%.f", 当前值)
		} else {
			返回值 = fmt.Sprintf("%f", 当前值)
		}
		return
	case float32:
		if float32(int(当前值)) == 当前值 {
			返回值 = fmt.Sprintf("%.f", 当前值)
		} else {
			返回值 = fmt.Sprintf("%f", 当前值)
		}
		return
	default:
		返回值 = fmt.Sprintf("%v", 任意数据)
		return
	}

	return

}

func 创建文本(原始文本 string, 赋值次数 int, 对应文本 ...any) (返回值 string) {
	赋值次数++
	if 赋值次数 > len(对应文本) {
		返回值 = 原始文本
		return
	}

	分割符 := "{" + fmt.Sprintf("%v", 赋值次数) + "}"
	分割组 := strings.Split(原始文本, 分割符)
	for i, v := range 分割组 {
		分割组[i] = 创建文本(v, 赋值次数, 对应文本...)
	}
	返回值 = strings.Join(分割组, any_到文本(对应文本[赋值次数-1]))
	return
}

// 密钥 长度必须 16/24/32长度
func 加密(被加密文本 string, 密钥 string) string {
	if len(被加密文本) < 1 || (len(密钥) != 16 && len(密钥) != 24 && len(密钥) != 32) {
		return ""
	}

	// 转成字节数组
	origData := []byte(被加密文本)
	k := []byte(密钥)
	// 分组秘钥
	block, err := aes.NewCipher(k)
	if err != nil {
		panic(fmt.Sprintf("密钥 长度必须 16/24/32长度: %s", err.Error()))
	}
	// 获取秘钥块的长度
	blockSize := block.BlockSize()
	// 补全码
	origData = pkCS7Padding(origData, blockSize)
	// 加密模式
	blockMode := cipher.NewCBCEncrypter(block, k[:blockSize])
	// 创建数组
	cryted := make([]byte, len(origData))
	// 加密
	blockMode.CryptBlocks(cryted, origData)
	//使用RawURLEncoding 不要使用StdEncoding
	//不要使用StdEncoding  放在url参数中回导致错误
	return base64.RawURLEncoding.EncodeToString(cryted)

}

// 密钥 长度必须 16/24/32长度
func 解密(被解密文本 string, 密钥 string) string {
	if len(被解密文本) < 1 || (len(密钥) != 16 && len(密钥) != 24 && len(密钥) != 32) {
		return ""
	}
	//使用RawURLEncoding 不要使用StdEncoding
	//不要使用StdEncoding  放在url参数中回导致错误
	crytedByte, _ := base64.RawURLEncoding.DecodeString(被解密文本)
	k := []byte(密钥)
	if len(crytedByte) == 0 {
		return ""
	} else if len(crytedByte)%16 != 0 && len(crytedByte)%24 != 0 && len(crytedByte)%32 != 0 {
		return ""
	}

	// 分组秘钥
	block, err := aes.NewCipher(k)
	if err != nil {
		panic(fmt.Sprintf("密钥 长度必须 16/24/32长度: %s", err.Error()))
	}
	// 获取秘钥块的长度
	blockSize := block.BlockSize()
	// 加密模式
	blockMode := cipher.NewCBCDecrypter(block, k[:blockSize])
	// 创建数组
	orig := make([]byte, len(crytedByte))
	// 解密
	blockMode.CryptBlocks(orig, crytedByte)
	// 去补全码
	orig = pkCS7UnPadding(orig)
	return string(orig)
}

// 补码
func pkCS7Padding(ciphertext []byte, blocksize int) []byte {
	padding := blocksize - len(ciphertext)%blocksize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(ciphertext, padtext...)
}

// 去码
func pkCS7UnPadding(origData []byte) []byte {
	length := len(origData)
	unpadding := int(origData[length-1])
	return origData[:(length - unpadding)]
}

func embed内存文件释放到目录(原文件 embed.FS, fs文件 fs.FS, 释放文件名称, 保存路径 string) (返回错误 error) {
	if !全_文本.P判断后缀(保存路径, "/") && !全_文本.P判断后缀(保存路径, `\`) {
		保存路径 = 保存路径 + "/"
	}
	// 遍历文件系统
	err := fs.WalkDir(fs文件, 释放文件名称, func(path string, d fs.DirEntry, err error) error {
		if err != nil {
			return err
		}
		if d.IsDir() {
			目录 := 保存路径 + path
			if !全_文件.P判断文件_是否存在(目录) {
				err = 全_文件.C创建目录(目录)
				if err != nil {
					return err
				}
			}
			fmt.Println("创建目录：", 目录)
		} else {
			目录 := 保存路径 + path
			数据, err := 原文件.ReadFile(path)
			if err != nil {
				return err
			}
			err = 全_文件.X写到_文件(目录, 数据)
			if err != nil {
				return err
			}
			fmt.Println("创建文件：", 目录)
		}
		return nil
	})

	返回错误 = err
	return
}

// copyFolder 复制文件夹及其内容到目标文件夹
func copyFolder(srcDir, dstDir string) error {
	// 检查源文件夹是否存在
	if _, err := os.Stat(srcDir); os.IsNotExist(err) {
		return fmt.Errorf("源文件夹 %s 不存在", srcDir)
	}

	// 检查目标文件夹是否存在，如果不存在则创建它
	if _, err := os.Stat(dstDir); os.IsNotExist(err) {
		err = os.MkdirAll(dstDir, 0755)
		if err != nil {
			return err
		}
	}

	// 遍历源文件夹中的文件和子文件夹
	files, err := os.ReadDir(srcDir)
	if err != nil {
		return err
	}
	for _, file := range files {
		srcPath := filepath.Join(srcDir, file.Name())
		dstPath := filepath.Join(dstDir, file.Name())

		// 判断文件或文件夹类型
		if file.IsDir() {
			// 如果是文件夹，则递归调用 copyFolder 函数进行复制
			err = copyFolder(srcPath, dstPath)
			if err != nil {
				return err
			}
		} else {
			// 如果是文件，则使用 io.Copy 复制文件内容
			input, err := os.Open(srcPath)
			if err != nil {
				return err
			}
			defer input.Close()

			output, err := os.Create(dstPath)
			if err != nil {
				return err
			}
			defer output.Close()

			_, err = io.Copy(output, input)
			if err != nil {
				return err
			}
		}
	}

	return nil
}
